package com.zzyl.nursing.service.impl;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.*;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.core.domain.entity.SysUser;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.nursing.dto.DeviceDTO;
import com.zzyl.nursing.dto.DeviceDetailsDTO;
import com.zzyl.nursing.vo.DeviceDetailVO;
import com.zzyl.nursing.vo.ProjectVO;
import com.zzyl.system.mapper.SysUserMapper;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Cache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.ehcache.EhCacheCache;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.domain.Device;
import com.zzyl.nursing.service.IDeviceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;

/**
 * 设备Service业务层处理
 *
 * @author 张三
 * @date 2025-07-05
 */
@Slf4j
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements IDeviceService {
    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private IoTDAClient iotClient;
    @Autowired
    private StringRedisTemplate redis;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Override
    public List<ProjectVO> getAllProduct() {
        try {
            String jsonStr = redis.opsForValue().get(CacheConstants.IOT_ALL_PRODUCT_LIST);
            List<ProductSummary> list = JSONUtil.toList(jsonStr, ProductSummary.class);
            return list.stream().map((s) -> {
                ProjectVO vo = new ProjectVO();
                vo.setProductKey(s.getProductId());
                vo.setProductName(s.getName());
                return vo;
            }).collect(Collectors.toList());
        }catch (Exception e){
            log.error("湖区产品列表失败，失败的原因：{}",e.getMessage());
        }
        return Collections.emptyList();
    }

    /**
     *
     */
    @Override
    public void syncProductListFromIot() {
        // 查询IOT 产品列表
        try {
            ListProductsRequest request = new ListProductsRequest();
            ListProductsResponse response = iotClient.listProducts(request);
            List<ProductSummary> products = response.getProducts();
            redis.opsForValue().set(CacheConstants.IOT_ALL_PRODUCT_LIST, JSONUtil.toJsonStr(products));
        } catch (Exception e) {
           log.error("获取产品列表s失败.",e.getMessage());
        }

    }


    @Override
    public DeviceDetailVO queryDeviceDetail(DeviceDetailsDTO dto) {
        // 查询IOT平台获取设备的状态和设备密钥
        ShowDeviceResponse resp = null;
        try {
            ShowDeviceRequest req = new ShowDeviceRequest();
            req.setDeviceId(dto.getIotId());
            resp = iotClient.showDevice(req);
        }catch (Exception e){
            log.error("查询IOT失败，{}",e.getMessage());
        }
        // 断言 优雅！如果resp 抛出运行时异常！ 处理空指针的第四种方法！
        assert resp != null;
        String status = resp.getStatus();
        String secret = resp.getAuthInfo().getSecret();
        String nodeType = resp.getNodeType();
        String authType = resp.getAuthInfo().getAuthType();
        String fwVersion = resp.getFwVersion();
        String createTime = resp.getCreateTime();
        String activeTime = resp.getActiveTime();
        // IOT 获取的时间处理
        LocalDateTime cDate = LocalDateTimeUtil.parse(createTime, "yyyyMMdd'T'HHmmss'Z'");
        LocalDateTime aDate = LocalDateTimeUtil.parse(activeTime, "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");


        // 查询数据库封装基础数据
        Device device = deviceMapper.selectOne(Wrappers.<Device>lambdaQuery().eq(Device::getIotId, dto.getIotId()));
        assert device != null;
        // 根据创建人id查询用户表获取用户名称
        SysUser sysUser = sysUserMapper.selectUserById(Long.parseLong(device.getCreateBy()));
        // 合并数据
        DeviceDetailVO vo = new DeviceDetailVO();
        // 从数据库获取的数据封装
        vo.setIotId(device.getIotId());
        vo.setDeviceName(device.getDeviceName());
        vo.setProductName(device.getProductName());
        vo.setRemark(device.getRemark());
        vo.setProductKey(device.getProductKey());
        vo.setNickname(device.getNickname());
        vo.setLocationType(device.getLocationType());
        vo.setNodeType(nodeType);
        vo.setAuthType(authType);
        vo.setFirmwareVersion(fwVersion);
        vo.setCreator(sysUser.getNickName());
        vo.setGmtCreate(cDate);
        vo.setGmtActive(aDate);

        // 从IOT 获取的数据封装
        vo.setDeviceSecret(secret);
        vo.setStatus(status);
        return vo;
    }



    @Transactional
    @Override
    public void registerDevice(DeviceDTO dto) {
        // 设备名称是否重复
        String deviceName = dto.getDeviceName();
        Device device1 = deviceMapper.selectOne(Wrappers.lambdaQuery(Device.class).eq(Device::getDeviceName, deviceName));
        if (ObjectUtil.isNotEmpty(device1)) {
            throw new RuntimeException("设备名称已经存在！");
        }
        // 同一位置是否绑定相同产品
        Device device2 = deviceMapper.selectOne(Wrappers.lambdaQuery(Device.class)
                .eq(Device::getLocationType, dto.getLocationType())
                .eq(Device::getRemark, dto.getRemark())
                .eq(Device::getProductKey, dto.getProductKey())
        );
        if (ObjectUtil.isNotEmpty(device2)) {
            throw new RuntimeException("同一个位置绑定了相同的设备!");
        }
        // 注册设备到IOT
        AddDeviceResponse addDeviceResponse;
        try {
            AddDeviceRequest request = new AddDeviceRequest();
            AddDevice body = new AddDevice();
            body.setDeviceName(dto.getNickname());
            body.setDescription(dto.getDeviceDescription());
            body.setProductId(dto.getProductKey());
            body.setNodeId(dto.getDeviceName());
            request.setBody(body);
            // 向iot注册设备
            addDeviceResponse = iotClient.addDevice(request);
        } catch (Exception e) {
            log.error("华为IOT创建设备失败，失败的原因是：{}", e.getMessage());
            throw new RuntimeException("华为IOT创建设备失败!");
        }
        // 保存设备信息和关系保存设备表
        // 获取注册设备id
        String deviceId = addDeviceResponse.getDeviceId();

        Device device = new Device();
        BeanUtil.copyProperties(dto, device);
        device.setIotId(deviceId);
        device.setHaveEntranceGuard(0);
        device.setDeviceDescription(dto.getBindingLocation()+"");
        // 简单的手动异步补偿
        try {
            deviceMapper.insert(device);
        }catch (Exception e){
            log.error("添加设备到数据库失败，失败的原因是：{}，失败数据是：{}", e.getMessage(),JSONUtil.toJsonStr(device));
            //TODO
            // 异步调用华为云客户端删除刚刚再华为云新增设备！ 【兜底方案 定时任务，终极方案手动补偿】
        }
    }



    /**
     * 查询设备
     *
     * @param id 设备主键
     * @return 设备
     */
    @Override
    public Device selectDeviceById(Long id) {
        return deviceMapper.selectById(id);
    }

    /**
     * 查询设备列表
     *
     * @param device 设备
     * @return 设备
     */
    @Override
    public List<Device> selectDeviceList(Device device) {
        return deviceMapper.selectDeviceList(device);
    }

    /**
     * 新增设备
     *
     * @param device 设备
     * @return 结果
     */
    @Override
    public int insertDevice(Device device) {
        return deviceMapper.insert(device);
    }

    /**
     * 修改设备
     *
     * @param device 设备
     * @return 结果
     */
    @Override
    public int updateDevice(Device device) {
        return deviceMapper.updateById(device);
    }

    /**
     * 批量删除设备
     *
     * @param ids 需要删除的设备主键
     * @return 结果
     */
    @Override
    public int deleteDeviceByIds(Long[] ids) {
        return deviceMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除设备信息
     *
     * @param id 设备主键
     * @return 结果
     */
    @Override
    public int deleteDeviceById(Long id) {
        return deviceMapper.deleteById(id);
    }
}
